﻿using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;

namespace Dot5Demo.Serials
{
    #region Converters

    public class DataXConverter : JsonConverter
    {
        public override bool CanConvert(Type objectType)
        {
            return objectType == typeof(DataX);
        }

        public string[] GetProportiesNames(DataXType dataXType)
        {
            var strs = new string[4];
            switch (dataXType)
            {
                case DataXType.Full:
                    strs[0] = "x";
                    strs[1] = "y";
                    strs[2] = "width";
                    strs[3] = "hight";
                    break;

                case DataXType.Abbr:
                    strs[0] = "x";
                    strs[1] = "y";
                    strs[2] = "w";
                    strs[3] = "h";
                    break;

                default:
                    strs[0] = "v0";
                    strs[1] = "v1";
                    strs[2] = "v2";
                    strs[3] = "v3";
                    break;
            }
            return strs;
        }

        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            if (!CanConvert(objectType))
                return null;
            var jobj = JObject.Load(reader);
            var data = new DataX();
            data.DType = (DataXType)Enum.Parse(typeof(DataXType), jobj.Value<string>("Type"));
            var keys = GetProportiesNames(data.DType);
            data.V0 = jobj.Value<float>(keys[0]);
            data.V1 = jobj.Value<float>(keys[1]);
            data.V2 = jobj.Value<float>(keys[2]);
            data.V3 = jobj.Value<float>(keys[3]);
            return data;
        }

        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            if (value == null)
                return;
            if (!CanConvert(value.GetType()))
                return;
            var data = value as DataX;
            writer.WriteStartObject();
            writer.WritePropertyName("Type");
            writer.WriteValue(data.DType.ToString());
            var keys = GetProportiesNames(data.DType);
            writer.WritePropertyName(keys[0]);
            writer.WriteValue(data.V0);
            writer.WritePropertyName(keys[1]);
            writer.WriteValue(data.V1);
            writer.WritePropertyName(keys[2]);
            writer.WriteValue(data.V2);
            writer.WritePropertyName(keys[3]);
            writer.WriteValue(data.V3);
            writer.WriteEnd();
        }
    }

    #endregion Converters

    public abstract class Graphics
    {
        public string Name { get; set; }
        public object Parent { get; set; }
    }

    public class Rect : Graphics
    {
        [JsonConverter(typeof(DataXConverter))]
        public DataX Data { get; set; }

        [JsonIgnore]
        public ComplexObj Obj { get; set; }

        public override bool Equals(object obj)
        {
            var n = obj as Rect;
            if (n == null)
                return false;
            if (Name != n.Name)
                return false;
            bool r = false;
            if (Data != null)
            {
                r = Data.Equals(n.Data);
            }
            else
            {
                r = n.Data == null;
            }
            if (!r)
                return false;
            bool l = false;
            if (Obj != null)
            {
                r = Obj.Equals(n.Obj);
            }
            else
            {
                r = n.Obj == null;
            }
            return r && l;
        }

        public override int GetHashCode()
        {
            throw new NotImplementedException();
        }
    }

    public sealed class ComplexObj
    {
        public ComplexObj()
        {
        }

        public string Name { get; set; }

        public double Value { get; set; }

        public override bool Equals(object obj)
        {
            if (obj == null || obj is not ComplexObj)
                return false;
            var n = obj as ComplexObj;
            return n.Name == Name
                && n.Value == Value;
        }

        public override int GetHashCode()
        {
            throw new NotImplementedException();
        }
    }

    [JsonConverter(typeof(DataXConverter))]
    public class DataX
    {
        public DataXType DType { get; set; }
        public float V0 { get; set; }
        public float V1 { get; set; }
        public float V2 { get; set; }
        public float V3 { get; set; }

        public override int GetHashCode()
        {
            return string.Format("{0}{1}{2}{3}{4}", DType, V0, V1, V2, V3).GetHashCode();
        }

        public override bool Equals(object obj)
        {
            if (obj == null || obj is not DataX)
                return false;
            var n = obj as DataX;
            return n.DType == DType
                && n.V0 == V0
                && n.V1 == V1
                && n.V2 == V2
                && n.V3 == V3;
        }
    }

    public enum DataXType
    {
        Full,
        Abbr,
    }
}